package lt.bcra.jwt;

import com.lt.bcra.exception.BaseException;
import com.lt.bcra.result.ResponseEnum;
import io.jsonwebtoken.*;
import org.springframework.util.StringUtils;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;
import java.util.UUID;

public class JwtHelper {
    //token的过期时间,一个小时
    private static long tokenExpiration = 24 * 60 * 60 * 1000;

    //token的生效时间,5秒
    private static long tokenNotBefore = 5 * 1000;

    //签名的密钥 根据所给的字符串通过算法获得加密
    private static String tokenSignKey = "lt1303241677";

    /**
     * 根据所给的参数获取token
     *
     * @param id
     * @param phone
     * @return
     */
    public static String createToken(Integer id, String phone) {
        String token = Jwts.builder()
                //头部信息
                .setHeaderParam("typ", "JWT")//令牌类型
                .setHeaderParam("alg", "HS256")//签名算法

                //载荷:自定义信息，需要加密参数
                .claim("id", id)
                .claim("phone", phone)

                //载荷:默认信息
                .setSubject("bcra-system")//令牌主题
                .setIssuer("LuoTian")//签发者
                .setAudience("LuoTian")//接收方
                .setIssuedAt(new Date())//令牌签发时间
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))//过期时间
                //.setNotBefore(new Date(System.currentTimeMillis() + tokenNotBefore))//生效时间
                .setId(UUID.randomUUID().toString())//唯一身份标识，避免重复攻击

                //签名哈希算法
                .signWith(SignatureAlgorithm.HS512, tokenSignKey)
                .compressWith(CompressionCodecs.GZIP)

                //对其进行组装
                .compact();
        return token;
    }

    /**
     * 根据token得到了用户id
     *
     * @param token
     * @return
     */
    public static Integer getId(String token) {
        if (StringUtils.isEmpty(token)) {
            throw new BaseException(ResponseEnum.WEIXIN_FETCH_ACCESSTOKEN_ERROR);
        }
        Jws<Claims> claimsJws = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        Integer id = (Integer) claims.get("id");
        return id;
    }

    /**
     * 根据了token得到了手机号
     *
     * @param token
     * @return
     */
    public static String getPhone(String token) {
        if (StringUtils.isEmpty(token)) {
            throw new BaseException(ResponseEnum.WEIXIN_FETCH_ACCESSTOKEN_ERROR);
        }
        Jws<Claims> claimsJws
                = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token);
        Claims claims = claimsJws.getBody();
        return (String) claims.get("phone");
    }

    private static Key getKeyInstance(){
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        byte[] bytes = DatatypeConverter.parseBase64Binary(tokenSignKey);
        return new SecretKeySpec(bytes,signatureAlgorithm.getJcaName());
    }

    /**
     * 判断token是否有效
     * @param token
     * @return
     */
    public static boolean checkToken(String token) {
        if(StringUtils.isEmpty(token)) {
            return false;
        }
        try {
            Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 测试类
     *
     * @param args
     */
    public static void main(String[] args) {
        String token = JwtHelper.createToken(1, "jack");
        System.out.println(token);
        System.out.println(JwtHelper.getId(token));
        System.out.println(JwtHelper.getPhone(token));
    }
}
